<template>
  <div class="home-container">
    <el-card shadow="always" style="margin-bottom:30px;">
      <div class="emq-title">
        My Configuration
      </div>
      <el-form ref="configForm" hide-required-asterisk size="small" label-position="top" :model="connection">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item prop="host" label="Host" required>
              <el-row :gutter="10">
                <el-col :span="7">
                  <el-select v-model="connection.protocol" @change="handleProtocolChange" :disabled="client.connected">
                    <el-option label="ws://" value="ws"></el-option>
                    <el-option label="wss://" value="wss"></el-option>
                  </el-select>
                </el-col>
                <el-col :span="17">
                  <el-input v-model="connection.host" placeholder="please enter ECS ip" :disabled="client.connected"></el-input>
                </el-col>
              </el-row>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="port" label="Port" required>
              <el-input v-model.number="connection.port" type="number" placeholder="8083/8883" :disabled="client.connected"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="endpoint" label="Mountpoint" required>
              <el-input v-model="connection.endpoint" placeholder="/mqtt" :disabled="client.connected"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="clientId" label="ClientID">
              <el-input v-model="connection.clientId" placeholder="please enter your clientId" :disabled="client.connected"> </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="username" label="Username" required>
              <el-input v-model="connection.username" :disabled="client.connected"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="password" label="Password" required>
              <el-input type="password" v-model="connection.password" clearable :disabled="client.connected"></el-input>
            </el-form-item>
          </el-col>

          <el-col :span="24">
            <el-button
              type="success"
              size="small"
              class="conn-btn"
              style="margin-right: 20px;"
              :disabled="client.connected || !connection.clientId"
              @click="createConnection"
              :loading="connecting"
            >
              {{ client.connected ? 'Connected' : 'Connect' }}
            </el-button>

            <el-button v-if="client.connected" type="danger" size="small" class="conn-btn" @click="destroyConnection">
              Disconnect
            </el-button>
          </el-col>
        </el-row>
      </el-form>
    </el-card>
    <el-card shadow="always" style="margin-bottom:30px;">
      <div class="emq-title">
        Subscribe
      </div>
      <el-form ref="subscription" hide-required-asterisk size="small" label-position="top" :model="subscription">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-form-item prop="topic" label="ReceivedID">
              <el-input v-model="subscription.topic" placeholder="please enter received clientId"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item prop="qos" label="QoS">
              <el-select v-model="subscription.qos">
                <el-option v-for="qos in qosList" :key="qos.value" :label="qos.label" :value="qos.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-button
              :disabled="!client.connected || !subscription.topic || subscribeSuccess"
              type="success"
              size="small"
              class="subscribe-btn"
              @click="doSubscribe"
              v-if="!subscribeSuccess"
            >
              {{ subscribeSuccess ? 'Subscribed' : 'Subscribe' }}
            </el-button>
            <el-button
              :disabled="!client.connected"
              type="danger"
              size="small"
              class="subscribe-btn"
              @click="doUnSubscribe"
              v-if="subscribeSuccess"
            >
              Unsubscribe
            </el-button>
            <el-button
              type="success"
              size="small"
              style="margin-bottom: 20px;"
              @click="clearMsg"
            >
              Clear
            </el-button>
          </el-col>
        </el-row>
      </el-form>
      <div class="emq-title" @click="hiddenMsg = true">
        Message Display
      </div>
      <el-col class="coverbg" :span="24">
        <div ref="receivor" class="msg-receivor" @mouseleave="hiddenMsg = true"></div>
        <div v-show="hiddenMsg" class="coverbg-item" @dblclick="hiddenMsg = false">
          MQTT协议是为大量计算能力有限，且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议，它具有以下主要的几项特性：<br>
          &emsp;&emsp; 1、使用发布/订阅消息模式，提供一对多的消息发布，解除应用程序耦合；<br>
          &emsp;&emsp; 2、对负载内容屏蔽的消息传输；<br>
          &emsp;&emsp; 3、使用 TCP/IP 提供网络连接； <br>
          &emsp;&emsp; 4、有三种消息发布服务质量： <br>
          &emsp;&emsp; 5、小型传输，开销很小（固定长度的头部是 2 字节），协议交换最小化，以降低网络流量；<br>
          &emsp;&emsp; 6、使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制。
        </div>
      </el-col>
    </el-card>
    <el-card shadow="always" style="margin-bottom:30px;">
      <div class="emq-title">
        Publish
      </div>
      <el-form ref="publish" hide-required-asterisk size="small" label-position="top" :model="publish">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-form-item prop="topic" label="SendID">
              <el-input v-model="publish.topic" placeholder="please enter clientId who you'll send"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item prop="payload" label="MsgText">
              <el-input v-model="publish.payload" placeholder="please enter content which send" @mouseenter.native="hiddenMsg = false" @mouseleave.native="hiddenMsg = true" @keyup.enter.native="doPublish"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item prop="qos" label="QoS">
              <el-select v-model="publish.qos">
                <el-option v-for="qos in qosList" :key="qos.value" :label="qos.label" :value="qos.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item prop="retain" label="Retain" title="Resend if not received">
              <el-switch v-model="publish.retain" active-color="#13ce66"> </el-switch>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-button
              :disabled="!client.connected || !publish.topic"
              type="success"
              size="small"
              class="subscribe-btn"
              @click="doPublish"
            >
              Publish
            </el-button>
          </el-col>
        </el-row>
      </el-form>
    </el-card>
  </div>
</template>

<script>
import { Message } from 'element-ui'
import mqtt from 'mqtt'
const msgFormat = (clientId, msg) => JSON.stringify({
  clientId,
  msg
});
export default {
  name: 'Home',
  data() {
    return {
      connection: {
        protocol: 'ws',
        host: '39.108.63.227',
        // ws: 8083; wss: 8883
        port: 8083,
        endpoint: '/mqtt',
        // for more options, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
        clean: true,
        connectTimeout: 40 * 1000, // ms
        reconnectPeriod: 4000, // ms
        clientId: '',
        // auth
        username: 'admin',
        password: '44663388',
      },
      subscription: {
        topic: '',
        qos: 0,
      },
      publish: {
        topic: '',
        qos: 0,
        retain: false,
        payload: '',
      },
      receiveNews: '',
      qosList: [
        {
          label: '0(At most once)',
          value: 0,
        },
        {
          label: '1(At least once)',
          value: 1,
        },
        {
          label: '2(Only once)',
          value: 2,
        },
      ],
      client: {
        connected: false,
      },
      subscribeSuccess: false,
      connecting: false,
      retryTimes: 0,
      hiddenMsg: true,
    }
  },
  methods: {
    clearMsg() {
      this.$refs.receivor.innerHTML = ''
    },
    inputMsg(msg, topic, type) {
      if (!this.$refs.receivor) return
      let p = document.createElement('p')
      p.className = `msg-item-${type}`
      p.innerHTML = `<h5 style="margin: 0;padding: 0;">me</h5>` + msg
      if (type === 'left') {
        p.innerHTML = `<h5 style="margin: 0;padding: 0;">${topic}</h5>` + msg
      }
      this.$refs.receivor.appendChild(p)
      this.$refs.receivor.scrollTop = this.$refs.receivor.scrollHeight
    },
    initData() {
      this.client = {
        connected: false,
      }
      this.retryTimes = 0
      this.connecting = false
      this.subscribeSuccess = false
    },
    handleOnReConnect() {
      this.retryTimes += 1
      if (this.retryTimes > 5) {
        try {
          this.client.end()
          this.initData()
          this.$message.error('Connection maxReconnectTimes limit, stop retry')
        } catch (error) {
          this.$message.error(error.toString())
        }
      }
    },
    createConnection() {
      const _this = this
      try {
        this.connecting = true
        const { protocol, host, port, endpoint, ...options } = this.connection
        const connectUrl = `${protocol}://${host}:${port}${endpoint}`
        this.client = mqtt.connect(connectUrl, options)
        if (this.client.on) {
          this.client.on('connect', () => {
            this.connecting = false
            console.log('Connection succeeded!')
            Message({
              message: 'Connection Succeeded!',
              type: 'success'
            });
            this.clearMsg()
          })
          this.client.on('reconnect', this.handleOnReConnect)
          this.client.on('error', error => {
            console.log('Connection failed', error)
          })
          this.client.on('message', (topic, message) => {
            const { clientId, msg } = JSON.parse(message.toString())
            if (topic === _this.subscription.topic && clientId !== _this.connection.clientId) {
              _this.inputMsg(msg, clientId, 'left')
            }
          })
        }
      } catch (error) {
        this.connecting = false
        console.log('mqtt.connect error', error)
      }
    },
    // subscribe topic
    // https://github.com/mqttjs/MQTT.js#mqttclientsubscribetopictopic-arraytopic-object-options-callback
    doSubscribe() {
      const { topic, qos } = this.subscription
      this.client.subscribe(topic, { qos }, (error, res) => {
        if (error) {
          console.log('Subscribe to topics error', error)
          return
        }
        this.subscribeSuccess = true
        console.log('Subscribe to topics res', res)
      })
    },
    // unsubscribe topic
    // https://github.com/mqttjs/MQTT.js#mqttclientunsubscribetopictopic-array-options-callback
    doUnSubscribe() {
      const { topic } = this.subscription
      this.client.unsubscribe(topic, error => {
        if (error) {
          console.log('Unsubscribe error', error)
        }
        this.subscribeSuccess = false
        console.log('UnSubscribe to topics')
      })
    },
    // publish message
    // https://github.com/mqttjs/MQTT.js#mqttclientpublishtopic-message-options-callback
    doPublish() {
      const reg = /<[^>]*>|&amp;nbsp;/g
      const { topic, qos, retain, payload } = this.publish
      if (!payload) return
      if (reg.test(payload)) {
        Message({
          message: 'Illegal String!',
          type: 'error'
        });
        return
      }
      const msgBody = msgFormat(this.connection.clientId, payload)
      this.client.publish(topic, msgBody, { qos, retain }, error => {
        if (error) {
          console.log('Publish error', error)
        }
        this.inputMsg(payload, null, 'right')
        this.publish.payload = ''
      })
    },
    // disconnect
    // https://github.com/mqttjs/MQTT.js#mqttclientendforce-options-callback
    destroyConnection() {
      if (this.client.connected) {
        try {
          this.client.end(false, () => {
            this.initData()
            Message({
              message: 'Disconnected!',
              type: 'error'
            });
            console.log('Successfully disconnected!')
          })
        } catch (error) {
          console.log('Disconnect failed', error.toString())
        }
      }
    },
    handleProtocolChange(value) {
      this.connection.port = value === 'wss' ? '8883' : '8083'
    },
  },
}
</script>

<style lang="scss">
@import url('../assets/style/home.scss');

.home-container {
  max-width: 1100px;
  margin: 0 auto;

  .conn-btn {
    color: #fff;
    background-color: #00b173;
    font-size: 14px;
  }

  .publish-btn {
    margin-bottom: 20px;
    float: left;
  }

  .el-button--success {
    background-color: #34c388 !important;
    border-color: #34c388 !important;
    font-size: 14px !important;
  }

  .el-button--danger {
    background-color: #f5222d !important;
    border-color: #f5222d !important;
  }

  .el-form-item {
    &.is-error {
      .el-input__inner,
      .el-textarea__inner {
        box-shadow: 0 0 0 2px rgba(245, 34, 45, 0.2);
      }
    }
    &.is-success {
      .el-input__inner,
      .el-textarea__inner {
        border-color: #34c388 !important;
      }
    }
  }

  .coverbg {
    position: relative;

    .coverbg-item {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: #fff;
      overflow: hidden;
    }
  }

  .msg-receivor {
    min-height: 80px;
    max-height: 250px;
    border: 1px solid #e4e4e4;
    border-radius: 5px;
    margin-bottom: 15px;
    padding: 5px;
    overflow: auto;
    scroll-behavior: smooth;

    &:active {
      border-color: rgb(70, 161, 254);
    }

    .msg-item-left {
      text-align: left;
    }
    .msg-item-right {
      text-align: right;
    }

    &::-webkit-scrollbar {
      width: 0;
    }
  }
}
</style>
